<script setup lang="ts">
/**
 * @prop {IForm[]} list - 可选, table-colume的配置项, 会设置到所有内容列, 对象属性与 element plus 官网在 el-table-colume 标签上的属性一致
 *    @typedef {object} IForm
 *          @property {string} label - 必填, 表单名称
 *          @property {string} prop - 必填, 字段名称
 *          @property {'select' | 'switch' | 'input' | 'number' | 'cascader' | 'treeSelect' | 'datePicker' | 'timePicker' | 'timeSelect' | 'radioGroup' | 'rate' | 'slider' | 'upload' | 'slot' | 'apiTreeSelect'} type - 必填, 表单种类
 *          @property {number} column - 可选, 这一项在此行占比, 例如 1 占满此行, 2 为此行一半
 *          @property {object} selectOption - 可选, { options: Array<any>; label?: string; value?: string; } options: 选择框列表, label: 自定义options中显示字段  value: 自定义options中绑定值字段
 *          @property {any} config - 可选, element plus 官网在 对应类型表单 标签上的属性
 * @prop {any} data - 必填, 与父组件双向绑定
 * @prop {FormRules} rules - 可选, element plus 规定的表单校验类型一致
 * @prop {number} column - 可选, 每一项在此行占比, 例如 1 占满此行, 2 为此行一半
 * @prop {Partial<FormProps>} config - 可选, 支持 element plus 在 Form 上的属性
 */
import { ElCol, ElForm } from 'element-plus';
import type { FormInstance, FormProps, FormRules } from 'element-plus';
import { computed, ref, toRefs } from 'vue';

import { IForm } from '@/types';

import FormCollection from './FormCollection.vue';

const prop = withDefaults(
  defineProps<{
    list: IForm[];
    data: Record<string, any>;
    rules?: FormRules;
    column?: number;
    config?: Partial<FormProps>;
    isEdit?: boolean;
    theme?: '' | 'theme1' | 'theme2';
  }>(),
  {
    rules: () => ({}),
    column: 1,
    isEdit: true,
    theme: '',
  },
);

const { data, isEdit, list } = toRefs(prop);
const dealList = computed<IForm[]>(() => {
  if (isEdit.value) return list.value;
  else return list.value.map((item) => ({ ...item, type: 'text' }));
});

const form = ref<FormInstance>();
function validate(callback: (valid: boolean) => void) {
  return form.value?.validate(callback);
}
function resetFields() {
  form.value?.resetFields();
}
function clearValidate() {
  form.value?.clearValidate();
}
defineExpose({
  resetFields,
  validate,
  clearValidate,
});
</script>

<template>
  <el-form :class="theme" ref="form" :model="data" status-icon label-width="auto" class="el-form" :rules="prop.rules" v-bind="config">
    <el-col
      v-for="item in dealList"
      :key="item.prop"
      :span="(24 / prop.column) * Math.min(item.column ?? 1, prop.column)"
      style="padding-right: 20px"
    >
      <FormCollection :item="item" v-model:data="data[item.prop]">
        <template v-if="item.type === 'slot'" #[item.prop]><slot :name="item.prop" :data="data"></slot></template>
      </FormCollection>
    </el-col>
  </el-form>
</template>

<style lang="scss" scoped>
.el-form {
  display: flex;
  flex-wrap: wrap;
}
.form-upload,
:deep(.el-select),
:deep(.el-input),
:deep(.el-input-number),
:deep(.el-input__wrapper),
:deep(.el-cascader),
:deep(.el-date-editor.el-input) {
  width: 100%;
}
.theme1 {
  --el-border-radius-base: 0;
  --el-border-radius-small: 0;
  :deep(.el-form-item__label) {
    background-color: var(--el-border-color);
    padding-left: 10px;
  }
  :deep(.el-col) {
    padding-right: 0 !important;
  }
  :deep(.el-form-item) {
    margin-bottom: 5px;
  }
  :deep(.m-text) {
    box-sizing: border-box;
    box-shadow: 0 0 0 1px var(--el-border-color) inset;
    padding: 0 10px;
    background-color: var(--el-input-bg-color);
  }
  :deep(.el-radio-group) {
    width: 100%;
    box-sizing: border-box;
    box-shadow: 0 0 0 1px var(--el-border-color) inset;
    padding: 0 10px;
  }
  :deep(.el-form-item--small .m-text) {
    padding: 0 6px;
  }
  :deep(.el-form-item--large .m-text) {
    padding: 0 14px;
  }
}
</style>
